/*
 * spektro.c
 *
 * Created: 10.01.2013 20:28:05
 *  Author: clemens
 */ 
#include "spektro.h"
#include "modes.h"
#include "FHT.h"
#include "UART_routines.h" 


int16_t minLvlAvg[8]; // For dynamic adjustment of low & high ends of graph,
int16_t  maxLvlAvg[8]; // pseudo rolling averages for the prior few frames.
uint8_t  peak[8];      // Peak level of each column; used for falling dots
uint8_t  dotCount = 0; // Frame counter for delaying dot-falling speed
uint8_t  colCount = 0; // Frame counter for storing past column data

uint8_t x, i;// y;// quiet;
uint8_t fadeR = 0;
uint8_t fadeG = 0;
uint8_t fadeB = 0;
uint8_t BGfadeR = 0;
uint8_t BGfadeG = 0;
uint8_t BGfadeB = 0;
//uint8_t invert=0;
uint16_t ct_fade = 0;
uint16_t ct_count = 0;
uint8_t c;
uint16_t level;
uint16_t minLvl;
uint16_t maxLvl;
uint8_t beat=0;
//uint32_t touchmem =0;

void capture_wave() {
	for (int i = 0 ; i < FHT_N ; i++) { // save 256 samples
	while(!(ADCSRA & 0x10)); // wait for adc to be ready
	ADCSRA = 0xf5; // restart adc
	//ADCSRA = 0xd5;
	uint8_t m = ADCL; // fetch adc data
	uint8_t j = ADCH;
	uint16_t k = (j << 8) | m; // form into an int
	k -= 0x0200; // form into a signed int
	k <<= 6; // form into a 16b signed int
	fht_input[i] = k; // put real data into bins
	//fht_input[i] = ADC ;//- 32768;
}
}
// calculate average values, history, uart ausgabe
void calculatebands(void)
{
	
	uint8_t sb;
	
		//subbander :		
		for(sb = 0; sb < 8; sb++) {
			
			// average history
			AvEs[sb]=0;
			for(uint8_t h = 0; h < 40; h++) {
				AvEs[sb] = AvEs[sb] + HisEs[sb][h];
			}
			//durchschnitt/40
			AvEs[sb]=(((uint32_t)AvEs[sb] * (uint32_t)0xCCCD) >> 16) >> 5;
			//durchschnitt/60
			//AvEs[sb]=(((uint32_t)AvEs[sb] * (uint32_t)0x8889) >> 16) >> 5;
			
			//transmitByte(AvEs[sb]);
			
			/*
			if (fht_oct_out[sb] <=  mini[sb]){
				mini[sb]=fht_oct_out[sb];
			}
			else if (fht_oct_out[sb] >=  maxi[sb]){
				maxi[sb]=fht_oct_out[sb];
			}*/
		}			
		
		
		//TX_NEWLINE;	
		//update history
		for( sb = 0; sb < 8; sb++) {
			for(uint8_t h = 0; h < 39; h++) {
				/*if (sb==2)
				{transmitByte(HisEs[2][h]);
				}*/
				
				HisEs[sb][h] = HisEs[sb][h+1];
			}
			/*if (sb==2)
			{transmitByte(HisEs[2][39]);
			}*/
			//if (fht_oct_out[sb]<=(AvEs[sb] >> 1)+(AvEs[sb] >> 2))
			/*if (fht_lin_out8[sb]<=(AvEs[sb] >> 1)+(AvEs[sb] >> 2))
			{HisEs[sb][39]=(AvEs[sb] >> 1)+(AvEs[sb] >> 2);
			}*/
			//else HisEs[sb][39]=fht_oct_out[sb];
			 
			HisEs[sb][39]=fht_oct_out[sb];
		}
		
		// offset abziehen	
		for( sb = 0; sb < 8; sb++) {
			if (fht_oct_out[sb] > AvEs[sb])
			{fht_oct_out[sb]= fht_oct_out[sb] - AvEs[sb] ;
			} 
			else
			{fht_oct_out[sb]=0;
			}
			//fht_log_out[sb]= fht_log_out[sb] - avzero[sb] ;
		//	transmitByte(fht_oct_out[sb]);
			}
		//TX_NEWLINE;	
		//TX_NEWLINE;
		//varianz
		/*
		for( sb = 0; sb < 8; sb++) {
			VaEs[sb]=0;
			for(uint8_t h = 0; h < 60; h++) {
				VaEs[sb] = VaEs[sb] + ((HisEs[sb][h]-AvEs[sb])*(HisEs[sb][h]-AvEs[sb]));		
			}
			VaEs[sb]=(((uint32_t)VaEs[sb] * (uint32_t)0x8889) >> 16) >> 5;
			//uint8_t low = (uint8_t)(VaEs[sb]);
			//uint8_t high = (uint8_t)(VaEs[sb] >> 8);
			//transmitByte(high);
			//transmitByte(low);
		}
		//TX_NEWLINE;
		*/
	
	
}

void samplefht(void)
{		
	fht_window(); // window the data for better frequency response
	fht_reorder(); // reorder the data before doing the fht
	fht_run(); // process the data in the fht
	fht_mag_octave(); // take the output of the fht
	//fht_mag_lin8();
	//fht_mag_log();
}

void showspectrum(){	
	
	 uint8_t summaxlvl=0;	
 static uint8_t summaxlvl_avg=0;
	
	//transmitByte(touchcountertime);
	//if (touchcountertime)				//wird hier anstelle von refreshtime verwendet, wird in touchmenue null gesetzt
	uint8_t refreshtime_local=refreshtime;
	if (mode_id!=14)
	{refreshtime_local=touchcountertime;
	}
	if (refreshtime_local)
	{	if (mode_id==14)
	{refreshtime = 0;
	}
	//refreshtime = 0;
		changetouchstatus();//damit touchstatus ungleich touchmem
		//transmitByte(254);
		cli();	
		capture_wave();	
		samplefht();			
		calculatebands();
		//transmitByte(0xaa);
		sei();
		//_delay_us(10);
		//TX_NEWLINE;
		
		//_delay_us(10);
		// Downsample spectrum output to 8 columns:
		
		for(x=1; x<6; x++) 
		{ 
    
			//col[x][colCount] = sum / colDiv[x];                    // Average
			minLvl = maxLvl = HisEs[x][39];
			//transmitByte(fht_oct_out[x]);
	
			for(i=0; i<40; i++) // Get range of prior 10 frames
			{ 
				if(HisEs[x][i] < minLvl)      minLvl = HisEs[x][i];
				else if(HisEs[x][i] > maxLvl) maxLvl = HisEs[x][i];
    
				if (minLvl > AvEs[x])
					{minLvl = minLvl - AvEs[x] ;
					} 
				else
					{minLvl=0;
					}
			
				if (maxLvl > AvEs[x])
					{maxLvl = maxLvl - AvEs[x] ;
					} 
				else
					{maxLvl=0;
					}
			}	
		
		//use maxLvl as indication for running music
		// minLvl and maxLvl indicate the extents of the FFT output, used
		// for vertically scaling the output graph (so it looks interesting
		// regardless of volume level).  If they're too close together though
		// (e.g. at very low volume levels) the graph becomes super coarse
		// and 'jumpy'...so keep some minimum distance between them (this
		// also lets the graph go to zero when no sound is playing):
		//transmitByte(maxLvl);
		//summaxlvl[9]=summaxlvl[9]+maxLvl;
		summaxlvl=summaxlvl+maxLvl;
		if((maxLvl - minLvl) < 25) 
			{
				maxLvl = minLvl + 25;
			}			
		minLvlAvg[x] = (minLvlAvg[x] * 7 + minLvl) >> 3; // Dampen min/max levels
		maxLvlAvg[x] = (maxLvlAvg[x] * 7 + maxLvl) >> 3; // (fake rolling average)
		//transmitByte(maxLvl);

		// Second fixed-point scale based on dynamic min/max levels:
		level = 10L * (fht_oct_out[x] - minLvlAvg[x]) /
		(long)(maxLvlAvg[x] - minLvlAvg[x]);

		// Clip output and convert to byte:
		if(level < 0L)      c = 0;
		else if(level > 10) c = 10; // Allow dot to go a couple pixels off top
		else                c = (uint8_t)level;

		if((c > peak[x])&(summaxlvl_avg>2)) 
		{
			peak[x] = c; // Keep dot on top
					
		}	
		if(++dotCount >= 6) {
			dotCount = 0;
			for(x=1; x<6; x++) {
				if(peak[x] > 0) peak[x]--;
			}
		}
	}
	//for (uint8_t cntsum=1; cntsum<10; cntsum++)
	summaxlvl_avg=(((uint32_t)(summaxlvl_avg)*15)+summaxlvl)>>4;
	summaxlvl=0;
}

}

void spectrum_fade(uint8_t color_status){

for (x=1;x<6;x++)
{

if ((ct_count>20)&&(x==2))
{
	ct_fade++;
	ct_count=0;
}

ct_count++;

if (ct_fade<60)
{
	fadeR = 59;
	fadeG = ct_fade;
	fadeB = 59 - ct_fade;
	BGfadeR = 0;
	BGfadeG = 0;
	BGfadeB = 0 ;
}
if ((ct_fade>=60)&(ct_fade<120))
{
	fadeR = 59-(ct_fade-60);
	fadeG = 59;
	fadeB = (ct_fade-60);
	BGfadeR = 0;
	BGfadeG = 0;
	BGfadeB = 0 ;
}
if ((ct_fade>=120)&(ct_fade<180))
{
	fadeR = (ct_fade-120);
	fadeG = 59-(ct_fade-120);
	fadeB = 59;
	BGfadeR = 0;
	BGfadeG = 0;
	BGfadeB = 0 ;
}
if ((ct_fade>=180)&(ct_fade<240))
{
	fadeR = (ct_fade-180);
	fadeG = 0;
	fadeB = 59-(ct_fade-180);
	if (color_status)
	{
		BGfadeR = 0;
		BGfadeG = (ct_fade-180);
		BGfadeB = 0;		
	}
	else
	{
		BGfadeR = 0;
		BGfadeG = 0;
		BGfadeB = 0 ;		
	}
}
if ((ct_fade>=240)&(ct_fade<300))
{
	fadeR = 59-(ct_fade-240);
	fadeG = (ct_fade-240);
	fadeB = 0;
	if (color_status)
	{
		BGfadeR = 0;
		BGfadeG = 59-(ct_fade-240);
		BGfadeB = (ct_fade-240);
	}
	else
	{
		BGfadeR = 0;
		BGfadeG = 0;
		BGfadeB = 0 ;
	}

}
if ((ct_fade>=300)&(ct_fade<360))
{
	fadeR = 0;
	fadeG = 59-(ct_fade-300);
	fadeB = (ct_fade-300);
	if (color_status)
	{
		BGfadeR = (ct_fade-300);
		BGfadeG = 0;
		BGfadeB = 59-(ct_fade-300);
	}
	else
	{
		BGfadeR = 0;
		BGfadeG = 0;
		BGfadeB = 0 ;
	}
}
if ((ct_fade>=360)&(ct_fade<420))
{
	fadeR = (ct_fade-360);;
	fadeG = 59-(ct_fade-360);
	fadeB = 59;
	if (color_status)
	{
	BGfadeR = 59-(ct_fade-360);
	BGfadeG = 0;
	BGfadeB = 0;
	}	
	else
	{
		BGfadeR = 0;
		BGfadeG = 0;
		BGfadeB = 0 ;
	}
}
if (ct_fade>=420)ct_fade =0;

if ((x>0)&(x<6))
{
	if (((((peak[x])>>1)))>1){
		drawLine(5-x, ((peak[x])>>1), 5-x, 4, BGfadeR,BGfadeG,BGfadeB);
		drawLine(5-x, 0, 5-x, ((peak[x])>>1), fadeR,fadeG,fadeB);
		//	drawLine(5-x, ((peak[x])>>1), 5-x, 4, 0,0,0);
		//	drawLine(5-x, 0, 5-x, ((peak[x])>>1), 0,59,0);
	}
	else
	{
		drawLine(5-x, 0, 5-x, ((peak[x])>>1), fadeR,fadeG,fadeB);
		drawLine(5-x, ((peak[x])>>1), 5-x, 4, BGfadeR,BGfadeG,BGfadeB);
	}
	
}
}
}



void detectbeat(){
			
		 if ((refreshtime==1)&&(peak[1]>=9))
			{	
				TCNT1=0;
				refreshtime=0;
// 				TX_NEWLINE;
// 				transmitByte(12);
// 				transmitByte(maxLvlAvg[1]);
				//fillScreen(59,0,0);
				beat=1;
			}
			else if ((refreshtime==1)&&(peak[2]>=9))
			{	
				TCNT1=0;
				refreshtime=0;
// 				TX_NEWLINE;
// 				transmitByte(22);
// 				transmitByte(maxLvlAvg[2]);
 				//fillScreen(0,59,0);
				 beat=1;
			}
			else 
			//fillScreen(0,0,0);
			beat=0;
			
			/*if ((refreshtime==1)&&(peak[3]>=9))
			{	TCNT1=0;
				refreshtime=0;
// 				TX_NEWLINE;
// 				transmitByte(32);
// 				transmitByte(maxLvlAvg[3]);
				fillScreen(0,0,59);
			}
			
			else if ((refreshtime==1)&&(peak[3]>=9))
				{
					refreshtime=0;
					transmitByte(42);
					fillScreen(0,0,59);
					
				}	
			else if ((refreshtime==1)&&(peak[4]>=9))
			{
				refreshtime=0;
				transmitByte(52);
				
			}*/
}